package com.gitee.sergius.apitool.parser;

import com.gitee.sergius.apitool.annotation.*;
import com.gitee.sergius.apitool.entity.ResponseParamEntity;
import com.gitee.sergius.apitool.entity.StatusCodeEntity;
import com.gitee.sergius.apitool.parser.convertor.request.ApiCustomerParamToEntityListConvertor;
import com.gitee.sergius.apitool.constant.MediaType;
import com.gitee.sergius.apitool.entity.RequestParamEntity;
import com.gitee.sergius.apitool.parser.convertor.request.ApiParamToEntityListConvertor;
import com.gitee.sergius.apitool.parser.convertor.response.ApiResponseToEntityListConvertor;
import com.gitee.sergius.apitool.parser.convertor.response.ReturnTypeResponseToEntityConvertor;
import com.gitee.sergius.apitool.parser.convertor.statuscode.ApiExceptionsToStatusCodeListConvertor;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;

/**
 * @author shawn yang
 * @version 1.0.0
 * <p><pre>用于解析方法上添加的注解</pre>
 *
 */
public class MethodAnnotationParser {

    /**
     * 解析出方法响应参数
     * @param method 要解析的方法
     * @return 用来存储解析出来的响应参数
     */
    public static List<ResponseParamEntity> parseMethodResponseParam(Method method){
        List<ResponseParamEntity> responseParamEntityList = new ArrayList<>();

        ApiResponse[] apiResponsesArr = null;
        if(method.isAnnotationPresent(ApiResponses.class)){
            apiResponsesArr = method.getAnnotation(ApiResponses.class).value();
        }else if(method.isAnnotationPresent(ApiResponse.class)){
            apiResponsesArr = new ApiResponse[]{method.getAnnotation(ApiResponse.class)};
        }
        if(apiResponsesArr != null && apiResponsesArr.length > 0){
            ApiResponseToEntityListConvertor.parse(apiResponsesArr,responseParamEntityList);
        }else{
            ReturnTypeResponseToEntityConvertor.parse(method,responseParamEntityList);
        }

        return responseParamEntityList;
    }

    /**
     * 解析出方法请求参数
     * @param method 要解析的方法
     * @return 用来存储解析出来的请求参数
     */
    public static List<RequestParamEntity> parseMethodRequestParam(Method method){
        List<RequestParamEntity> requestParamEntityList = new ArrayList<>();

        Annotation[] aa = method.getDeclaredAnnotations();

        ApiCustomerParam[] apiCustomerParamArr = null;
        if(method.isAnnotationPresent(ApiCustomerParams.class)){
            apiCustomerParamArr = method.getAnnotation(ApiCustomerParams.class).value();
        }else if(method.isAnnotationPresent(ApiCustomerParam.class)){
            apiCustomerParamArr = new ApiCustomerParam[]{method.getAnnotation(ApiCustomerParam.class)};
        }
        if(apiCustomerParamArr != null && apiCustomerParamArr.length > 0){
            ApiCustomerParamToEntityListConvertor.parse(apiCustomerParamArr,requestParamEntityList);
        }else{
            Parameter[] requestParams =  method.getParameters();
            ApiParamToEntityListConvertor.parse(requestParams,requestParamEntityList);
        }


        return  requestParamEntityList;
    }

    /**
     * 解析出方法描述，由Api#desc定义
     * @param method 要解析的方法
     * @return 方法描述
     */
    public static String parseMethodDesc(Method method){
        if(method.isAnnotationPresent(Api.class)){
            return method.getAnnotation(Api.class).desc();
        }

        return "";
    }

    /**
     * 解析出方法上定义的content-type ，由Api#contentType定义
     * @param method 要解析的方法
     *  @return 解析出来的请求content-type {@link MediaType}
     */
    public static MediaType parseMethodMediaType(Method method ){
        MediaType mediaType = null;
        if(method.isAnnotationPresent(Api.class)){
            mediaType = method.getAnnotation(Api.class).contentType();
        }
        return mediaType;
    }


    /**
     * 解析出方法上定义的tag分组标签
     * @param method 要解析的方法
     * @return 分组标签名称，若未定义，返回""
     */
    public static String  parseMethodTag(Method method){
        if(method.isAnnotationPresent(Api.class)){
            return method.getAnnotation(Api.class).tag();
        }

        return "";
    }



    /**
     * 解析方法上定义的响应码
     * @param method 要解析的方法
     *  @return 存储解析出来的响应码信息
     */
    public static List<StatusCodeEntity> parseMethodStatusCodeList(Method method){

        List<StatusCodeEntity> statusCodeList = new ArrayList<>();

        ApiException[] apiExceptionArr = null;
        if(method.isAnnotationPresent(ApiExceptions.class)){
            apiExceptionArr = method.getAnnotation(ApiExceptions.class).value();
        }else if(method.isAnnotationPresent(ApiException.class)){
            apiExceptionArr = new ApiException[]{method.getAnnotation(ApiException.class)};
        }
        if(apiExceptionArr != null && apiExceptionArr.length > 0){
            ApiExceptionsToStatusCodeListConvertor.parse(apiExceptionArr,statusCodeList);
        }

        return statusCodeList;
    }

    /**
     * 解析出方法上面定义的请求url ，RequestMapping#value
     * @param method 要解析的方法
     * @param parentUrlList 类上面定义请求url，如果此项有值传入，将根据类上定义的url和方法上定义的url生成最终的url
     * @return 接口请求url列表
     */
    public static List<String> parseMethodUrlList(Method method,List<String> parentUrlList){

        List<String> urlList ;

        if(method.isAnnotationPresent(RequestMapping.class)){
            String[] requestMappingValus = method.getAnnotation(RequestMapping.class).value();
            if(requestMappingValus != null){

                urlList = getUrlListByParentAndChild(parentUrlList,requestMappingValus);

            }else{
                urlList = parentUrlList;
            }
        }else{
            urlList = parentUrlList;
        }
        return urlList;

    }

    /**
     * 解析出方法上定义的请求方式，由RequestMapping#method定义，
     * @param method 要解析的方法
     * @return 存储解析出来的请求方式
     */
    public static List<RequestMethod> parseMethodRequestMethod(Method method){

        List<RequestMethod> requestMethodList = new ArrayList<>();

        if(method.isAnnotationPresent(RequestMapping.class)){
            RequestMethod[] requestMappingValus = method.getAnnotation(RequestMapping.class).method();
            if(requestMappingValus != null){
                for(RequestMethod rmethod : requestMappingValus){
                    requestMethodList.add(rmethod);
                }
            }
        }
        return requestMethodList;

    }


    private static List<String> getUrlListByParentAndChild(List<String> parentUrlList , String[] requestMappingValus){
        List<String> urlList = new ArrayList<>();
        if(CollectionUtils.isEmpty(parentUrlList)){
            for(String value : requestMappingValus){
                if(!value.startsWith("/")){
                    value = "/" + value;
                }
                urlList.add(value);
            }
        }else{
            for(String parentUrl : parentUrlList){
                for(String childUrl : requestMappingValus){
                    String combineUrl = getSingleUrl(parentUrl,childUrl);
                    if(!combineUrl.startsWith("/")){
                        combineUrl = "/" + combineUrl;
                    }
                    urlList.add(combineUrl);
                }
            }
        }
        return urlList;
    }

    private static String getSingleUrl(String parent,String child){
        String url ;
        if(parent.endsWith("/")){
            if(child.startsWith("/")){
                url = parent + child.substring(1);
            }else{
                url = parent + child;
            }
        }else{
            if(child.startsWith("/")){
                url = parent + child;
            }else{
                url = parent + "/" + child;
            }
        }

        return url;

    }


}
